package org.l.qiao;

import com.mongodb.BasicDBObject;
import com.mongodb.WriteConcern;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.model.UpdateOptions;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.apache.log4j.Logger;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.l.qiao.connect.MongoDB;
import org.l.qiao.builder.Query;
import org.l.qiao.web.KeyUpdate;
import org.springframework.beans.factory.annotation.Autowired;

import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by 严秋旺 on 2015/1/6.
 * 数据集操作DAO
 */
public abstract class AbstractCollectionDAO {

    private static final Logger LOGGER = Logger.getLogger(AbstractCollectionDAO.class);

    @Autowired
    protected MongoDB nosql;
    private String collection;
    private WriteConcern writeConcern = WriteConcern.ACKNOWLEDGED;
    private String name = "";


//    /**
//     * @param nosql      数据库连接
//     * @param collection 集合名称
//     */
//    public AbstractCollectionDAO(MongoDB nosql, String collection) {
//        this.nosql = nosql;
//        this.collection = collection;
//    }

    /**
     * @param collection 集合名称
     */
    public AbstractCollectionDAO(String collection) {
        //this.nosql = nosql;
        this.collection = collection;
    }

    public void setNosql(MongoDB nosql) throws UnknownHostException {
        nosql.init();
        this.nosql = nosql;
    }

    public MongoDB getNosql() {
        return nosql;
    }

    public MongoCollection<Document> getCollection(String collection) {
        return this.getNosql().getCollection(collection);
    }

    public MongoCollection<Document> getCollection() {
        return getCollection(collection);
    }

    public void setCollection(String collection) {
        this.collection = collection;
    }

    public String getName() {
        return name;
    }

    public WriteConcern getWriteConcern() {
        return writeConcern;
    }

    public void setWriteConcern(WriteConcern writeConcern) {
        this.writeConcern = writeConcern;
    }

    /**
     * 查询
     *
     * @param queryMap 搜索条件
     * @return 返回单个对象
     */
    public Cluster findOne(Cluster queryMap) {
        return findOne(queryMap, null);
    }

    /**
     * 查询
     *
     * @param queryMap 查询条件
     * @param fieldMap 查询列
     * @return 返回单个对象
     */
    public Cluster findOne(Cluster queryMap, Cluster fieldMap) {
        BasicDBObject query = null;

        if (queryMap != null) {
            query = new BasicDBObject(queryMap);
        }

        FindIterable<Document> findIterable = this.getCollection().find(query);

        if (fieldMap != null) {
            findIterable.projection(new BasicDBObject(fieldMap));
        }

        Document document = findIterable.first();

        if (document != null) {
            return new Cluster(document);
        } else {
            return null;
        }
    }

    /**
     * 查询
     *
     * @param querymap 查询条件
     * @param fieldmap 查询字段
     * @param sortmap  排序条件
     * @return 返回对象列表
     */
    public List<Cluster> find(Cluster querymap, Cluster fieldmap, Cluster sortmap) {
        BasicDBObject ref = new BasicDBObject();

        if (querymap != null) {
            ref = new BasicDBObject(querymap);
        }

        FindIterable<Document> findIterable = this.getCollection().find(ref);


        if (fieldmap != null) {
            findIterable.projection(new BasicDBObject(fieldmap));
        }

        if (sortmap != null) {
            findIterable.sort(new BasicDBObject(sortmap));
        }

        List<Cluster> list = toList(findIterable.iterator());
        return list;
    }

    /**
     * 取出游标内容，并关闭
     *
     * @param mongoCursor
     * @return
     */
    protected List<Cluster> toList(MongoCursor<Document> mongoCursor) {
        List<Cluster> list = new ArrayList<>();

        try {

            while (mongoCursor.hasNext()) {
                list.add(new Cluster(mongoCursor.next()));
            }

        } catch (Exception e) {
            throw e;
        } finally {
            if (mongoCursor != null) {
                mongoCursor.close();
            }
        }

        return list;
    }

    /**
     * 通过ID查询
     *
     * @param id 对象唯一id
     * @return 单个对象
     */
    public Cluster findById(String id) {
        BasicDBObject bdb = new BasicDBObject();
        bdb.put("_id", new ObjectId(id));
        Document document = this.getCollection().find(bdb).first();

        if (document != null) {
            return new Cluster(document);
        } else {
            return null;
        }
    }

    /**
     * 分页查询
     *
     * @param query 搜索条件
     * @param field 查询键
     * @param sort  排列键
     * @param page  分页对象
     * @return 返回包含分页信息与列表的Map
     */
    public List<Cluster> findPage(Cluster query, Cluster field, Cluster sort, Page page) {
        List<Cluster> list = findList(query, field, sort, page);
        page.setSum(count(query));
        return list;
    }

    /**
     * 分页查询，但不查询总数
     *
     * @param query 查询条件
     * @param field 查询键
     * @param sort  排序键
     * @param page  分页对象
     * @return 查询列表
     */
    public List<Cluster> findList(Cluster query, Cluster field, Cluster sort, Page page) {
        BasicDBObject querybdb = null;
        if (query != null) {
            querybdb = new BasicDBObject(query);
        }

        FindIterable<Document> findIterable = this.getCollection().find(querybdb);

        if (field != null) {
            findIterable.projection(new BasicDBObject(field));
        }

        if (sort != null) {
            findIterable.sort(new BasicDBObject(sort));
        }

        findIterable.skip((page.getIndex() - 1) * page.getSize()).limit(page.getSize());
        List list = toList(findIterable.iterator());
        return list;
    }

    /**
     * 查询数量
     *
     * @param query 查询条件
     * @return 数量
     */
    public long count(Cluster query) {
        if (query == null) {
            return this.getCollection().count(new BasicDBObject());
        } else {
            return this.getCollection().count(new BasicDBObject(query));
        }
    }

    public int insert(Cluster data) {
        this.getCollection().insertOne(new Document(data));
        return 0;
    }

    public int insert(List<Cluster> datas) {
        List dbos = new ArrayList();

        for (Cluster cluster : datas) {
            dbos.add(new Document(cluster));
        }

        this.getCollection().insertMany(dbos);
        return 0;
    }

    /**
     * 将新数据替换数据库中的旧数据
     *
     * @param cluster 待保存的新数据
     * @return
     */
    public long save(Cluster cluster) {

        if (cluster.containsKey(Cluster.ID)) {
            Query query = new Query(Cluster.ID, cluster.get(Cluster.ID));
            cluster.remove(Cluster.ID);
            return replace(query, cluster, true);
        } else {
            return insert(cluster);
        }

    }

    public long update(KeyUpdate keyUpdate) {
        Cluster queryMap = new Cluster();
        queryMap.put(Cluster.ID, keyUpdate.parseId());
        Cluster updateMap = new Cluster();
        updateMap.put(keyUpdate.getName(), keyUpdate.parseValue());
        return updateSetOne(queryMap, updateMap);
    }

    /**
     * 设置键值
     * 修改多行，不插入
     *
     * @param querymap  查询条件
     * @param updatemap 修改内容
     * @return
     */
    public long updateSet(Cluster querymap, Cluster updatemap, boolean upsert, boolean multil) {
        Cluster update = null;
        if (updatemap != null) {
            update = new Cluster();
            update.put("$set", updatemap);
        }
        return update(querymap, update, upsert, multil);
    }

    public long updateSetOne(Cluster querymap, Cluster updatemap) {
        Cluster update = null;

        if (updatemap != null) {
            update = new Cluster();
            update.put("$set", updatemap);
        }
        return update(querymap, update, false, false);
    }

    public long updateOne(Cluster querymap, Cluster updatemap) {
        return update(querymap, updatemap, false, false);
    }

    /**
     * 删除键
     *
     * @param querymap
     * @param updatemap
     * @return
     */
    public long updateUnset(Cluster querymap, Cluster updatemap) {
        Cluster update = null;
        if (updatemap != null) {
            update = new Cluster();
            update.put("$unset", updatemap);
        }
        return updateOne(querymap, update);
    }

    /**
     * 修改
     *
     * @param querymap  查询条件
     * @param updatemap 修改内容
     * @param upsert    是否插入
     * @param multil    是否修改多行
     * @return
     */
    public long update(Cluster querymap, Cluster updatemap, boolean upsert, boolean multil) {
        BasicDBObject query = null;
        BasicDBObject update = null;
        if (querymap != null) {
            query = new BasicDBObject(querymap);
        }
        if (updatemap != null) {
            update = new BasicDBObject(updatemap);
        }
        return update(query, update, upsert, multil);
    }

    protected long update(BasicDBObject query, BasicDBObject update, boolean upsert, boolean multil) {
        UpdateResult updateResult;
        UpdateOptions updateOptions = new UpdateOptions();
        updateOptions.upsert(upsert);

        if (multil) {
            updateResult = getCollection().updateMany(query, update, updateOptions);
        } else {
            updateResult = getCollection().updateOne(query, update, updateOptions);
        }

        return updateResult.getMatchedCount();
    }

    public long replace(Cluster query, Cluster newValue, boolean upsert) {
        UpdateOptions updateOptions = new UpdateOptions();
        updateOptions.upsert(upsert);
        UpdateResult updateResult = getCollection().replaceOne(new Document(query), new Document(newValue), updateOptions);
        return updateResult.getMatchedCount();
    }

    public long removeById(String id) {
        Cluster searhMap = new Cluster();
        searhMap.put(Cluster.ID, new ObjectId(id));
        return remove(searhMap, false);
    }

    /**
     * 删除多条记录
     *
     * @param queryMap
     * @return
     */
    public long remove(Cluster queryMap) {
        return remove(queryMap, true);
    }

    public long remove(Cluster queryMap, boolean mutil) {
        return this.remove(new BasicDBObject(queryMap), mutil);
    }

    /**
     * 删除记录
     *
     * @param query  过滤条件
     * @param multil 是否删除多行
     * @return 删除行数
     */
    protected long remove(BasicDBObject query, boolean multil) {
        DeleteResult deleteResult;

        if (multil) {
            deleteResult = getCollection().deleteMany(query);
        } else {
            deleteResult = getCollection().deleteOne(query);
        }

        return deleteResult.getDeletedCount();
    }

    protected boolean remove(BasicDBObject query, boolean multil, boolean purge) {
        Document document = getCollection().findOneAndDelete(query);
        getCollection("share").insertOne(document);
        return false;
    }

    public Cluster findAndRemove(Cluster querymap) {
        Document document = getCollection().findOneAndDelete(new BasicDBObject(querymap));
        if (document == null) {
            return new Cluster();
        } else {
            return new Cluster(document);
        }
    }
}
